import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:ui' as ui;

import 'package:crypto/crypto.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:path_provider/path_provider.dart';

Future<Image> netWorkImageWithUrl(String imageUrl,
    {BoxFit fit = BoxFit.cover}) async {
  final localPath = await cachPath(imageUrl);
  Image? image = await readCashImage(localPath, fit: fit);
  if (image != null) {
    return image;
  }
  final ByteData data =
      await NetworkAssetBundle(Uri.parse(imageUrl)).load(imageUrl);
  final Uint8List bytes = data.buffer.asUint8List();
  File imageFile = File(localPath);
  await imageFile.writeAsBytes(bytes);
  return Image.memory(bytes, fit: fit);
}

Future<ui.Image?> netWorkUiImageWithUrl(String imageUrl) async {
  final localPath = await cachPath(imageUrl);
  ui.Image? image = await readCashUiImage(localPath);
  if (image != null) {
    return image;
  }
  final Uint8List bytes = await downImageWithUrl(imagePath: imageUrl);
  final Completer<ui.Image> completer = Completer();
  ui.decodeImageFromList(bytes, (ui.Image img) {
    completer.complete(img);
  });
  return completer.future;
}

Future<Uint8List> downImageWithUrl(
    {required String imagePath, bool cache = true}) async {
  final ByteData data =
      await NetworkAssetBundle(Uri.parse(imagePath)).load(imagePath);
  Uint8List bytes = data.buffer.asUint8List();
  if (cache) {
    final localPath = await cachPath(imagePath);
    File imageFile = File(localPath);
    await imageFile.writeAsBytes(bytes);
  }

  return bytes;
}

Future<Image?> readCashImage(String imageUrl,
    {BoxFit fit = BoxFit.cover}) async {
  Uint8List? imageBytes = await readCashData(imageUrl);
  return imageBytes != null ? Image.memory(imageBytes, fit: fit) : null;
}

Future<ui.Image?> readCashUiImage(String imageUrl) async {
  Uint8List? imageBytes = await readCashData(imageUrl);
  final Completer<ui.Image> completer = Completer();
  if (imageBytes == null) return null;
  ui.decodeImageFromList(imageBytes, (ui.Image img) {
    completer.complete(img);
  });
  return completer.future;
}

Future<Uint8List?> readCashData(String path) async {
  File file = File(path);
  bool exists = await file.exists();
  if (exists) {
    return await file.readAsBytes();
  }
  return null;
}

Future<String> cachPath(String imageUrl) async {
  String? lastString = imageUrl.split('.').last;
  if (lastString.length > 5) {
    lastString = "png";
  }
  Directory directory = await getApplicationDocumentsDirectory();
  return '${directory.path}/' "${generateMd5(imageUrl)}.$lastString";
}

String generateMd5(String input) {
  return md5.convert(utf8.encode(input)).toString();
}
